﻿using System;
using System.Collections.Specialized;
using System.Globalization;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using Barbar.MapReport.DataSource.Entities;
using Barbar.MapReport.DataSource.Resources;
using System.Web;

namespace Barbar.MapReport.DataSource {
  internal class RegionGeometryProviderFile : RegionGeometryProvider {
    private string m_Path;
    private XPathNavigator m_Navigator;
    private static XmlSerializer _PolygonSerializer = new XmlSerializer(typeof(RawPolygon), Constants.DataSourceXmlNamespace);
    private static object _SyncRoot = new object();
    

    public override void Initialize(string name, NameValueCollection config) {
      base.Initialize(name, config);

      if (config == null)
        throw new ArgumentNullException("config");

      m_Path = config["path"];
      if (String.IsNullOrEmpty(m_Path))
        throw new DataSourceException(Translator.Error_PathNotSpecified);

      if (HttpContext.Current != null && m_Path.StartsWith("~", StringComparison.Ordinal)) {
        m_Path = HttpContext.Current.Server.MapPath(m_Path);
      }

      if (!File.Exists(m_Path))
        throw new DataSourceException(Translator.Error_FileNotFound);
    }

    private void EnsureNavigator() {
      if (m_Navigator == null) {
        FileInfo fileInfo = new FileInfo(m_Path);
        using (FileStream stream = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read)) {
          XPathDocument document = new XPathDocument(stream);
          m_Navigator = document.CreateNavigator();
          stream.Close();
        }
      }
    }

    public override bool ContainsRegionGeometry(string regionId, ZoomLevel zoomLevel) {
      if (String.IsNullOrEmpty(regionId))
        throw new ArgumentNullException("regionId");

      EnsureNavigator();

      XmlNamespaceManager namespaceManager = new XmlNamespaceManager(m_Navigator.NameTable);
      namespaceManager.AddNamespace("d", Constants.DataSourceXmlNamespace);
      XPathNavigator navigator = m_Navigator.SelectSingleNode(String.Format(CultureInfo.InvariantCulture, "//d:RegionGeometry/d:Region[@id_Region='{0}' and @id_ZoomLevel='{1}']", regionId, zoomLevel.Id), namespaceManager);
      return navigator != null;
    }
  

    public override Polygon GetRegionGeometry(string regionId, ZoomLevel zoomLevel) {
      if (String.IsNullOrEmpty(regionId))
        throw new ArgumentNullException("regionId");

      RawPolygon result = null;

      EnsureNavigator();

      XmlNamespaceManager namespaceManager = new XmlNamespaceManager(m_Navigator.NameTable);
      namespaceManager.AddNamespace("d", Constants.DataSourceXmlNamespace);
      XPathNavigator navigator = m_Navigator.SelectSingleNode(String.Format(CultureInfo.InvariantCulture, "//d:RegionGeometry/d:Region[@id_Region='{0}' and @id_ZoomLevel='{1}']", regionId, zoomLevel.Id), namespaceManager);
      if (navigator == null)
        throw new DataSourceException(Translator.Error_RegionOrZoomLevelNotFound);

      using (XmlReader reader = navigator.ReadSubtree()) {
        lock (_SyncRoot) {
          result = (RawPolygon)_PolygonSerializer.Deserialize(reader);
        }
      }
      return result.ToPolygon();
    }
  }
}
